package com.liuyucheng.idea_springboot.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

/**
 * Springboot中使用注解实现过滤器，必须加上@Component注解
 */
@Slf4j
@Component
//@Order(value = 1)
//@WebFilter(filterName = "myFilter",urlPatterns = "/*")
public class MyFilter implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
//        System.out.println("调用了我的filter的init()方法");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
//        System.out.println("进入myFilter，请求："+request.getRequestURL()+"["+request.getMethod()+"]");
        String methodType = request.getMethod();
        String url = request.getRequestURL().toString();
        log.info("收到{}请求:{}",methodType,url);

        //拦截非法的http请求
        if (StringUtils.equals(methodType,"TRACE")){
            response.setContentType("text/plain;charset=UTF-8");
            response.setStatus(405);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());

            PrintWriter writer = response.getWriter();
            writer.write("不支持的请求方法");
            writer.flush();
            // 关键：显式关闭输出流(SpringBoot内置的Tomcat在过滤器的response返回之后又进行了处理，关闭输出流后Tomcat就不再处理了)
            writer.close();

            return;
        }

        /*
        在设置OPTIONS跨域响应headers的时候，添加 Access-Control-Max-Age ，
        这个参数的意思是把 OPTIONS 响应缓存起来，在指定的时间内，不会再次发起 OPTIONS 预请求，
        这样只有在第一次请求的时候会有 OPTIONS ，之后浏览器会从缓存里读取响应，也就不会再发送OPTIONS请求了
         */
        if("OPTIONS".equals(methodType)){
            // 后端设置，2592000，单位秒，也就是30天，如果是一天，就是86400
            response.addHeader( "Access-Control-Max-Age", "2592000" );
        }

        //origin漏洞修复
        String requestOrigin = request.getHeader("origin");
        if (requestOrigin != null && isRightHost(requestOrigin)){
            response.setStatus(403);
            return;
        }

        //禁用不安全的http请求
        response.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS");

        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
//        System.out.println("我的filter被销毁了");
        Filter.super.destroy();
    }

    /**
     * 来自请求的origin如果不是指定的合法的origin，直接过滤返回请求失败
     * @param requestOrigin origin
     * @return 结果
     */
    public boolean isRightHost(String requestOrigin){
        //挡板
        return false;
//        if (!StringUtils.equals(requestOrigin,"http://localhost:9527")){
//            //域名非法
//            log.info("非法的origin：" + requestOrigin);
//            return true;
//        }
//        log.info("合法的origin：" + requestOrigin);
//        return false;
    }
}
